package dk.dtu.is.controllers;

import java.io.IOException;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;

/**
 *  This is a very simple class that acts as the HTTP REST Client for the IEC 61850 REST Server.
 * 
 *  The server is the one that <a href="http://www.cee.dtu.dk/English/People.aspx?lg=showcommon&id=22997&type=publications">Anders Bro Pedersen</a> implemented during his Master Thesis at CEE.
 *  The reference paper for the server implementation is <a href="http://orbit.dtu.dk/fedora/objects/orbit:59637/datastreams/file_5186490/content">Facilitating a Generic Communication Interface to Distributed Energy Resources</a>
 *  
 * @author dsac
 * @date 10-Nov-2012
 *
 */
public class Iec61850HttpRestClient {
	
	HttpClient httpRestClient;
	
	/**
	 * Default constructor
	 */
	public Iec61850HttpRestClient() {
		httpRestClient = new DefaultHttpClient();
	}
	
	/**
	 * Initialize the client.
	 * This method should always be called before using the Http REST Client. 
	 */
	public void init() {
		httpRestClient = new DefaultHttpClient();
	}
	
	/**
	 * Shutdown the client
	 * Deallocate system resources when the Http REST Client is no longer needed.
	 */
	public void close() {
        // When HttpClient instance is no longer needed, shut down the connection manager to ensure
        // immediate deallocation of all system resources
		httpRestClient.getConnectionManager().shutdown();
	}

	/**
	 * Retrieve a resource from the IEC 61850 REST server.
	 * This is the main method in this class. It uses the GET method to access a HTTP resource
	 * being made available by the IEC 61850 server. 
	 * 
	 * @param path the full address of the remote resource to access
	 * Examples:
	 * <ul>
	 * 	<li>http://10.59.16.211:8081/T2GCHR/ZCEV1</li> 
	 * 	<li>http://10.59.16.211:8081/T2GCHR</li>
	 * 	<li>http://10.59.16.211:8081/T2GCHR/ZCEV1.SOC</li>
	 * </ul>
	 * 
	 * @return the full string node retrieved from the server, that is, an XML String.
	 */
	public String getNode(String path) {
		String node = null;
		try {
			// create the request
	        HttpGet httpget = new HttpGet(path);
	        
	        // Create a response handler: I use a String to begin with 
	        // In reality what I get is an XML response that I will have to process somehow
	        ResponseHandler<String> responseHandler = new BasicResponseHandler();
	        
	        // execute the request and use the response handle to decode the response
	        // this gives me a IEC 61850 node
	        node = httpRestClient.execute(httpget, responseHandler);
	    } catch (ClientProtocolException e) {
	    	System.err.println("Error in sending the Http request to the IEC Server. Error: " + e.getMessage());
			e.printStackTrace();
		} catch (IOException e) {
			System.err.println("Error in sending the Http request to the IEC Server. Error: " + e.getMessage());
			e.printStackTrace();
		}
		
		return node;
	}
	
	/**
	 * Same as {@link #getNode(String path) getNode} with support for query strings.
	 * 
	 * The response from the GET requests to the resources can be modified by using query
	 * string  parameters. Three query string parameters are defined:
	 * <ul>
	 * 	<li>expandLevel</li> 
	 * 	<li>fc</li>
	 * 	<li>includeValues</li>
	 * </ul>
	 * 
	 * @param path 
	 * 
	 * @param expandLevel it controls how big a portion of the data model is retrieved. 
	 * The default value of this parameter is zero, which results in only the requested 
	 * level of the data model being retrieved. Setting the expandLevel parameter to a 
	 * higher number or to the value {@literal "all"}, allows the client to retrieve bigger portions
	 * of the data-model hierarchy. By retrieving the whole data model, the client can 
	 * easily inspect an entire logical device and a single URL can therefore replace 
	 * multiple ACSI services.
	 * <ul>
	 * 	<li>Example1: "1"</li> 
	 * 	<li>Example2: "all"</li>
	 * </ul>
	 * 
	 * @param fc  used for filtering the data-model hierarchy to include only data attributes
	 * with the specified functional constraint
	 * The functional constraints are defined in IEC61850-7-2 
	 * <ul>
	 * 	<li>Example1: "MX"</li> 
	 * 	<li>Example2: "CO"</li>
	 * </ul>
	 * 
	 * @param includeValues specifies whether the data values should be included 
	 * in the response in addition to the data model
	 * More documentation needed for this query string
	 * 
	 * @return the full string node retrieved from the server, that is, an XML String. 
	 */
	public String getNode(String path, String expandLevel, String fc, String includeValues) {
		// I build the full path for the REST server
		// Example: http://10.59.16.211:8081/T2GCHR/ZCEV1?expandLevel=all&fcMX=&includeValues=true
		String fullPath = path;
		boolean hasExpandLevel = false;
		boolean hasFc = false;
		boolean hasIncludeValues = false;
		
		if (expandLevel!=null && expandLevel!="")
			hasExpandLevel = true;
		if (fc!=null && fc!="")
			hasFc = true;
		if (includeValues!=null && includeValues!="")
			hasIncludeValues = true;
		
		// add the "&" if I have other query string
		if (hasExpandLevel || hasFc || hasIncludeValues)
			fullPath += "?";
		
		// add the expandLevel
		if (hasExpandLevel) {
			fullPath += "expandLevel=" + expandLevel;
			if (hasFc || hasIncludeValues)
				fullPath += "&";
		}
		
		// add the expand Level
		if (hasFc) {
			fullPath += "fc=" + fc;
			if (hasIncludeValues)
				fullPath += "&";
		}
		
		// add the includeValues
		if (hasIncludeValues) {
			fullPath += "includeValues=" + includeValues;
		}
				
		// call the method
		return this.getNode(fullPath);
	}
}
